using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace TBit {
    public class Language {
        public enum TokenType {
            Number,
            Word,
            LanguageWord,
            LimitSymbol,
            OperSymbol,
            Other = -1
        }

        public class Token {
            public TokenType type;
            public string str;
        }

        /*
            if(xxx){}else{}
            loop(i = 0 , 10) {}

        */

        public List<string> language_words = new List<string>{
            "var","if","loop","else",
        };

        public List<string> limit_symbol_words = new List<string>{
            "(",")","[","]","{","}",","
        };

        public List<string> oper_symbol_words = new List<string>{
            "+","-","*","/",">","<",">=","<=","==","!=","!",
            "="
        };

        public List<char> symbol_words = new List<char>(){
            '+','-','*','/','=','>','<','(',')','[',']',
            '{','}',',','!','&','|'
        };

        public bool IsLanguageWord(string str) {
            return language_words.Contains(str);
        }

        public bool IsNumberWord(string str) {
            return Regex.IsMatch(str,@"(\-|\+)?\d+(\.\d+)?");
        }

        public bool IsLimitSymbol(string str) {
            return limit_symbol_words.Contains(str);
        }

        public bool IsOperSymbol(string str) {
            return oper_symbol_words.Contains(str);
        }

        public bool IsSkip(char c) {
            return c >= 0 && c <= 32;
        }

        public bool IsSymbolWord(char c) {
            return symbol_words.Contains(c);
        }

        public bool IsWord(string str) {
            return Regex.IsMatch(str,@"[a-zA-z_]+([a-zA-z_0-9]+)?");
        }

        public TokenType GetWordType(string str) {
            if(IsLanguageWord(str)) return TokenType.LanguageWord;
            if(IsWord(str)) return TokenType.Word;
            if(IsNumberWord(str)) return TokenType.Number;
            if(IsLimitSymbol(str)) return TokenType.LimitSymbol;
            if(IsOperSymbol(str)) return TokenType.OperSymbol;
            return TokenType.Other;
        }

        public string ReadWorld_Number(string code,ref int i){
            bool is_point = false;
            char c;
            string word = "";
            for(;i<code.Length;i++)
            {
                c = code[i];
                if(!IsNumber(c) && c != '.')
                {
                    i--;
                    break;
                }
                if(c == '.')
                {
                    if(is_point)
                    {
                        i--;
                        break;
                    }
                    is_point = true;
                }
                word += c;
            }
            return word;
        }

        public static bool IsNumber(char c) {
            return c >= 48 && c <= 57;
        }

        public static bool IsLetter(char c) {
            return (c >= 65 && c <= 90) ||  (c >= 97 && c <= 122);
        }

        public string ReadWord(string code,ref int i) {
            char c = code[i];
            string word = "";
            if(IsLetter(c) || c == '_')
            {
                for(;i<code.Length;i++)
                {
                    c = code[i];
                    if(!IsLetter(c) && c != '_')
                    {
                        i--;
                        break;
                    }
                    word += c;
                }
            }
            else if(IsNumber(c)) {
                word = ReadWorld_Number(code,ref i);
            }
            else if(IsSymbolWord(c))
            {
                if(c == '-' && IsNumber(code[i + 1]))
                {
                    word += c;
                    i++;
                    word += ReadWorld_Number(code,ref i);
                    return word;
                }
                c = code[i];
                if(!IsSymbolWord(c)) return word;
                word += c;
                i++;
                c = code[i];
                if(!IsSymbolWord(c)) {
                    i--;
                    return word;
                }
                word += c;
            }
            return word;
        }

        public List<Token> ProcessWord(string code) {
            List<Token> words = new List<Token>();

            for(int i = 0;i< code.Length;)
            {
                if(!IsSkip(code[i]))
                {
                    string word = ReadWord(code,ref i);
                    Token tk = new Token();
                    TokenType type = GetWordType(word);
                    tk.str = word;
                    tk.type = type;
                    if(type != TokenType.Other)
                    {
                        words.Add(tk);
                    }
                }
                i++;
            }

            return words;
        }
    }
}